/**
 * Evironment: names storage.
 */
class Environment {
  /**
   * Creates an environment with the given record.
   */
  constructor(record = {}, parent = null) {
    // 记录所有的变量定义及值
    this.record = record;

    this.parent = parent;
  }

  /**
   * Creates a variable with the given name and value.
   */
  define(name, value) {
    this.record[name] = value;
    return value;
  }

  /**
   * Returns the value of a defined variable, or throws
   * if the variable is not defined.
   */
  lookup(variableName) {
    return this.resolve(variableName).record[variableName];
  }

  /**
   * Updates an existing variable.
   */
  assign(variableName, value) {
    // 变量重新赋值
    this.resolve(variableName).record[variableName] = value;
    return value;
  }

  /**
   * Returns specific environment in which a variable is defined, or throws
   * if the variable is not defined.
   */
  resolve(variableName) {
    if (this.record.hasOwnProperty(variableName)) {
      return this;
    }

    if (this.parent == null) {
      throw new ReferenceError(`Variable "${variableName}" is not defined.`);
    }

    // 向上寻找是否已经定义的变量
    return this.parent.resolve(variableName);
  }
}

module.exports = Environment;
